#pragma once

#include "comm/my_str.h"
#include "comm/my_queue.h"
#include "comm/my_rbtree.h"
#include "comm/my_pool.h"

// there may be multiple headers with the same name in headers.
// so we use same_headers manage these headers of the same name.
// the rbtree is used to quickly find the header.
// queue_in_headers is used to ensure the order of headers.
// queue_in_same_headers is used to manage headers of the same name.

typedef struct {
    my_queue_t          queue_in_headers;
    my_queue_t          queue_in_same_headers;
    my_str_t            name;
    my_str_t            value;
} my_http_header_t;

typedef struct {
    my_rbtree_node_t    tree_node;
    my_queue_t          headers;
    my_str_t            name;
} my_http_same_headers_t;

static inline void
my_http_same_headers_init(my_http_same_headers_t *same_headers)
{
    my_queue_init(&same_headers->headers);
}

static inline int
my_http_same_headers_cmp(my_rbtree_node_t *a, my_rbtree_node_t *b)
{
    my_http_same_headers_t *hdrs_a, *hdrs_b;
    hdrs_a = (my_http_same_headers_t *)a;
    hdrs_b = (my_http_same_headers_t *)b;
    return my_str_case_cmp(&hdrs_a->name, &hdrs_b->name);
}

typedef struct {
    my_pool_t           *pool;
    my_queue_t          headers;
    my_rbtree_t         same_headers_tree;
    my_rbtree_node_t    same_headers_sentinel;
} my_http_headers_t;

static inline void
my_http_headers_init(my_http_headers_t *headers, my_pool_t *pool)
{
    headers->pool = pool;
    my_queue_init(&headers->headers);
    my_rbtree_init(&headers->same_headers_tree,
        &headers->same_headers_sentinel,
        my_http_same_headers_cmp);
}

// use this method to directly modify the value
// of the header without affecting the order of the header.
static inline void
my_http_header_update(my_http_header_t *header, my_str_t *new_value)
{
    header->value = *new_value;
}

// add http_header to http_headers and http_same_headers.
// the end of the new adding will be append to the queue.
void my_http_headers_add(my_http_headers_t *headers, my_http_header_t *header);

// use http_headers to covery http_same_headers in http headers.
// the end of the new setting will be appended to the queue.
void my_http_headers_set(my_http_headers_t *headers, my_http_header_t *header);

// use name to get http header.
// if has multiple headers with the same name in headers,
// only the first one will be returned.
my_http_header_t *my_http_headers_get(my_http_headers_t *headers, my_str_t *name);

// return all headers matching name.
// the http_headers_add, http_headers_set and http_headers_del* 
// may cause http_same_headers to be modified.
// the same_headers obtained before http_headers_add and http_headers_set
// can no longer be used.
my_http_same_headers_t *my_http_headers_values(my_http_headers_t *headers, my_str_t *name);

void my_http_headers_del(my_http_headers_t *headers, my_http_header_t *header);

void my_http_headers_del_by_name(my_http_headers_t *headers, my_str_t *name);

// dump header for test
void my_http_header_dump(my_http_header_t *header);

// dump same headers for test
void my_http_same_headers_dump(my_http_same_headers_t *same_headers);

// dump headers for test
void my_http_headers_dump(my_http_headers_t *headers);
